﻿#include "Atom.h"
#include <iostream>
#include "Track.h"



const ATOM_BODY know_atom[] = {
	{"ftyp",{"file_level"},ATOMTYPE::CHILD_ATOM},
	{"free",{"file_level"},ATOMTYPE::CHILD_ATOM},
	{"mdat",{"file_level"},ATOMTYPE::CHILD_ATOM},
	{"moov",{"file_level"},ATOMTYPE::PARENT_ATOM},
	{"mvhd",{"moov"},ATOMTYPE::CHILD_ATOM},
	{"trak",{"moov"},ATOMTYPE::PARENT_ATOM},
	{"tkhd",{"trak"},ATOMTYPE::CHILD_ATOM},
	{"edts",{"trak"},ATOMTYPE::PARENT_ATOM},
	{"elst",{"edts"},ATOMTYPE::CHILD_ATOM},
	{"mdia",{"trak"},ATOMTYPE::PARENT_ATOM},
	{"mdhd",{"mdia"},ATOMTYPE::CHILD_ATOM},
	{"hdlr",{"mdia"},ATOMTYPE::CHILD_ATOM},
	{"minf",{"mdia"},ATOMTYPE::PARENT_ATOM},
	{"vmhd",{"minf"},ATOMTYPE::CHILD_ATOM},
	{"dinf",{"minf"},ATOMTYPE::PARENT_ATOM},
	{"dref",{"dinf"},ATOMTYPE::CHILD_ATOM},
	{"url",{"dref"},ATOMTYPE::CHILD_ATOM},
	{"stbl",{"minf"},ATOMTYPE::PARENT_ATOM},
	{"stsd",{"stbl"},ATOMTYPE::DUAL_STATE_ATOM},
	{"avc1",{"stsd"},ATOMTYPE::DUAL_STATE_ATOM},
	{"avcC",{"avc1"},ATOMTYPE::CHILD_ATOM},
	{"stts",{"stbl"},ATOMTYPE::CHILD_ATOM},
	{"stss",{"stbl"},ATOMTYPE::CHILD_ATOM},
	{"stsc",{"stbl"},ATOMTYPE::CHILD_ATOM},
	{"stsz",{"stbl"},ATOMTYPE::CHILD_ATOM},
	{"stco",{"stbl"},ATOMTYPE::CHILD_ATOM},
	{"udta",{"moov"},ATOMTYPE::PARENT_ATOM},
	{"meta",{"udat"},ATOMTYPE::DUAL_STATE_ATOM},
	{"hdlr",{"meta"},ATOMTYPE::CHILD_ATOM},
	{"ilst",{"meta"},ATOMTYPE::PARENT_ATOM}
};



int Atom::ParseHeader(File& file)
{
	start = file.Pos();
//	content_start = start + 8;
	atom_size = file.read_int();
	if (atom_size < 0) {
		return -1;
	}
	
	char type[5] = {};
	file.read(type, 4);
	boxType = type;
	// large size
	if (atom_size == 0) {
		atom_size = file.read_int64();
//		content_start += 8;
		BoxSize16 = true;
	}
	return 0;
}

bool Atom::IsPartentBox(std::string name)
{
	for (int i(0); i < 30; i++) {
		if (name == know_atom[i].atom_name) {
			return know_atom[i].type == ATOMTYPE::PARENT_ATOM;
		}
	}
	return false;
}






int Atom::ParseAtom(File& file,int64_t readSize)
{
	content_data = new char[readSize];
	return file.read(content_data, readSize);
}

int Atom::WriteAtomHead(File& fp)
{
	char atomHead[32] = {};
	int length = 0;
	char data[8] = {};

	if (BoxSize16) {
		//		length = snprintf(atomHead, 32, "%04d%s%08ld", 1, boxType.c_str(), data);
	}
	else {
		num_to_char(atom_size, atomHead, 4);
		snprintf(atomHead + 4, 32, "%s", boxType.c_str());
		length = 8;
	}
	length = fp.Write(atomHead, length);
	if (length <= 0) {
		std::cerr << "erro write atom head " << boxType << std::endl;
	}
	return length;
}

int64_t Atom::SerializeAtom(File& fp)
{

	if (IsPartentBox(boxType)) {
		atom_size = 8;
		int64_t pos = fp.Pos();
		WriteAtomHead(fp);
		for (auto& iter : childAtom) {
			atom_size += iter->SerializeAtom(fp);
		}
		char actSize[4] = {};
		num_to_char(atom_size, actSize, 4);

		int64_t nowPos = fp.Pos();

		if (fp.Seek(pos, SEEK_SET) < 0) {
			std::cerr << "error seek to " << pos << std::endl;
		}
		fp.Write(actSize, 4);
		fp.Seek(nowPos, SEEK_SET);
	}
	else {
		int headLen = WriteAtomHead(fp);
		if (atom_size - headLen > 0 && fp.Write(content_data, atom_size - headLen) > 0) {

		}
	}
	
	std::cout << "type " << boxType << " size " << std::hex <<atom_size << std::endl;
	return atom_size;
}

Atom* Atom::FindAtomName(std::string boxName)
{
	for (auto chAtom : childAtom) {
		if (chAtom->AtomType() == boxName) {
			return chAtom;
		}

		Atom* ch2 = chAtom->FindAtomName(boxName);
		if (ch2)
			return ch2;
	}

	return nullptr;
}

std::shared_ptr<char> Atom::readData(File& file, int64_t readSize)
{
	if ((readSize <= 0) || readSize > (file.Size() - file.Pos())) {
		std::cerr << "error read size\n";
		return nullptr;
	}

	std::shared_ptr<char> mediaData(new char[readSize]);
	int64_t len = file.read(mediaData.get(), readSize);
	if (len <= 0) {
		std::cerr << "error read file\n";
		return nullptr;
	}
	return mediaData;
}


Atom::~Atom()
{
	if (content_data) {
		delete[] content_data;
	}
	for (auto var : childAtom)
	{
		delete(var);
	}
	childAtom.clear();
}

int Atom::Parser(File& file)
{
	if (ParseHeader(file) < 0)
		return -1;

	
//	std::cout << "file end " << file.IsEnd() << " pos " << file.Pos() << " type " << boxType << std::endl;
	size_t ret = 0;
	if (IsPartentBox(boxType)/* && boxType != "udta"*/) {
		while (file.Pos() < start + atom_size) {
			// 提前窥视box类型
			char head[9] = {};
			file.read(head, 8);
			file.Seek(-8);
			std::cout << "next atom type " << head+4 << std::endl;

			Atom* atom = AtomFactory::CreateAtom(head + 4);
			atom->Parser(file);
			childAtom.push_back(atom);
		}

	}
	else {
		int64_t readSize = (BoxSize16 ? atom_size - 16 : atom_size - 8);
		if (readSize > file.Size() - file.Pos()) {
			std::cerr << "error readsize out of file\n";
			return -1;
		}
		// mdat 数据太大，不做存储  // udat 暂时也跳过
		if (boxType == "mdat" /*|| strcmp(boxType, "udta") == 0*/) {
			ret = file.Seek(readSize);
		}
		else {
			
			return ParseAtom(file, readSize);
		}
	}
	
	return 0;
}

// data 需包含atom头
void Atom::SetContentData(char* data, int64_t len)
{
	if (content_data) {
		delete[] content_data;
		content_data = nullptr;
	}

	content_data = new char[len]();
	memcpy(content_data, data, len);
	atom_size = len + 8;
}


Atom::Atom(const char* type) :
	start(0),
	content_data(nullptr),
	BoxSize16(false)
{
	if (type) {
		atom_size = 8;
		boxType.assign(type);
	}
}









/*************************************分隔*****************************************/

MvhdAtom::MvhdAtom()
{
	memset(&mvhd, 0,sizeof(MVHDBOX));
}

MvhdAtom::~MvhdAtom()
{

}

int MvhdAtom::ParseAtom(File& file, int64_t readSize)
{
	auto mediaData = readData(file, readSize);
	if (mediaData != nullptr) {
		char* p = mediaData.get();
		memcpy(mvhd.vf, p, 4);
		p += 4;

		char_to_num(p, 4, mvhd.media.create_time);
		p += 4;

		char_to_num(p, 4, mvhd.media.modify_time);
		p += 4;

		char_to_num(p, 4, mvhd.media.timescale);
		p += 4;
		
		char_to_num(p, 4, mvhd.media.duration);
		p += 4;

		// rate
		int32_t rate;
		char_to_num(p, 2, rate);
		mvhd.rate = rate;
		p += 2;
		char_to_num(p, 2, rate);
		mvhd.rate += rate / 100000.0;
		p += 2;

		// volume
		mvhd.volume = *p;
		mvhd.volume += *(p + 1) / 1000.0;
		p += 2;

		memcpy(mvhd.reserved, p, 10);
		p += 10;
		// 变换矩阵
		memcpy(mvhd.matrix, p, 36);
		p += 36;

		// pre-define 24bit,全部写入0
		p += 24;

		char_to_num(p, 4, mvhd.next_tid);

//		std::cout << " refence " << mediaData.use_count() << std::endl; 
		return 0;
	}

	
	return -1;
}

int64_t MvhdAtom::SerializeAtom(File& fp)
{
	int cSize = atom_size - WriteAtomHead(fp);
	if (cSize < 8) {
		std::cerr << "error atom size < 8 error\n";
		return -1;
	}
	char* data = new char[cSize]();

	int offset = 0;
	// version flag
	memcpy(data, mvhd.vf, 4);
	offset += 4;

	num_to_char(mvhd.media.create_time, data + offset,4);
	offset += 4;
	num_to_char(mvhd.media.modify_time, data + offset, 4);
	offset += 4;
	num_to_char(mvhd.media.timescale, data + offset, 4);
	offset += 4;
	num_to_char(mvhd.media.duration, data + offset, 4);
	offset += 4;

	// rate 
	num_to_char(1, data + offset, 2);

	offset += 4;
	//volume
	data[offset] = 1;
//	num_to_char(mvhd.volume, data + offset, 4);
	offset += 2;

	memcpy(data + offset, mvhd.reserved, 10);
	offset += 10;

	memcpy(data + offset, mvhd.matrix, 36);
	offset += 36;

	// pre-define 24bit,全部写入0
	memset(data + offset, 0, 24);
	offset += 24;

	num_to_char(mvhd.next_tid, data + offset, 4);
	offset += 4;


	if (fp.Write(data, cSize) < offset) {
		delete[] data;
		std::cerr << "error write mvhd head\n";
		return -1;
	}

	delete[] data;
	return atom_size;
}


TkhdAtom::TkhdAtom()
{
	memset(&tkhd, 0, sizeof(TKHDBOX));
}

TkhdAtom::~TkhdAtom()
{

}

int TkhdAtom::ParseAtom(File& file, int64_t readSize)
{
	auto mediaData = readData(file, readSize);
	if (mediaData != nullptr) {
		char* p = mediaData.get();
		memcpy(tkhd.vf, p, 4);
		p += 4;

		char_to_num(p, 4, tkhd.media.create_time);
		p += 4;

		char_to_num(p, 4, tkhd.media.modify_time);
		p += 4;

		char_to_num(p, 4, tkhd.trackid);
		p += 4;
		// 4保留位，用0填补
		p += 4;
		
		char_to_num(p, 4, tkhd.media.duration);
		p += 4;

		// 8保留位，用0填补
		p += 8;

		// layer
		char_to_num(p, 2, tkhd.layer);
		p += 2;
		// track info
		char_to_num(p, 2, tkhd.alternate_group);
		p += 2;

		//volume
		tkhd.volume = *p;
		tkhd.volume += (*p) / 1000.0;
		p += 2;
		//保留位
		p += 2;

		// martix 变换矩阵复用mvhd的参数
		memcpy(tkhd.matrix, p, 36);
		p += 36;
		
		int val;
		char_to_num(p, 2, tkhd.width);
		p += 4;

		char_to_num(p, 2, tkhd.height);
		p += 4;

		return 0;
	}
	return -1;
}

int64_t TkhdAtom::SerializeAtom(File& fp)
{
	int cSize = atom_size - WriteAtomHead(fp);
	if (cSize < 8) {
		std::cerr << "error atom size < 8 error\n";
		return -1;
	}
	char* data = new char[cSize]();

	int offset = 0;
	// version flag
	memcpy(data, tkhd.vf, 4);
	offset += 4;

	num_to_char(tkhd.media.create_time, data + offset, 4);
	offset += 4;
	num_to_char(tkhd.media.modify_time, data + offset, 4);
	offset += 4;
	num_to_char(tkhd.trackid, data + offset, 4);
	offset += 4;
	// 预留位
	offset += 4;

	num_to_char(tkhd.media.duration, data + offset, 4);
	offset += 4;

	// 预留位
	offset += 8;

	num_to_char(tkhd.layer, data + offset, 2);
	offset += 2;

	num_to_char(tkhd.alternate_group, data + offset, 2);
	offset += 2;
	
	data[offset] = 1;// (char)tkhd.volume;
	data[offset + 1] = 0;// (tkhd.volume - (int)data[offset]) * 100;
	offset += 2;

	// 保留位
	offset += 2;

	memcpy(data+offset, tkhd.matrix,36);
	offset += 36;

	num_to_char(1920, data + offset, 2);
	offset += 4;

	num_to_char(1080, data + offset, 2);
	offset += 4;

	
	if (fp.Write(data, cSize) < offset) {
		delete[] data;
		std::cerr << "error write tkhd head\n";
		return -1;
	}
	delete[] data;
	return atom_size;
}




MdhdAtom::MdhdAtom()
{
	memset(&mdhd, 0, sizeof(MdhdBox));
}

MdhdAtom::~MdhdAtom()
{

}

int MdhdAtom::ParseAtom(File& file, int64_t readSize)
{
	auto mediaData = readData(file, readSize);
	if (mediaData != nullptr) {
		char* p = mediaData.get();
		memcpy(mdhd.vf, p, 4);
		p += 4;

		char_to_num(p, 4, mdhd.media.create_time);
		p += 4;

		char_to_num(p, 4, mdhd.media.modify_time);
		p += 4;

		char_to_num(p, 4, mdhd.media.timescale);
		p += 4;

		char_to_num(p, 4, mdhd.media.duration);
		p += 4;

		mdhd.language_code[0] = *p;
		mdhd.language_code[1] = *(p + 1);
		p += 2;

		mdhd.pre_defined[0] = *p;
		mdhd.pre_defined[1] = *(p + 1);
		
		return 0;
	}
	return -1;
}

int64_t MdhdAtom::SerializeAtom(File& fp)
{
	int cSize = atom_size - WriteAtomHead(fp);
	if (cSize < 8) {
		std::cerr << "error atom size < 8 error\n";
		return -1;
	}
	char* data = new char[cSize]();
	
	int offset = 0;
	// version flag
	memcpy(data, mdhd.vf, 4);
	offset += 4;

	num_to_char(mdhd.media.create_time, data + offset, 4);
	offset += 4;
	num_to_char(mdhd.media.modify_time, data + offset, 4);
	offset += 4;
	num_to_char(mdhd.media.timescale, data + offset, 4);
	offset += 4;
	num_to_char(mdhd.media.duration, data + offset, 4);
	offset += 4;

	data[offset] = mdhd.language_code[0];
	data[offset+1] = mdhd.language_code[1];
	offset += 2;

	offset += 2;


	if (fp.Write(data, cSize) < offset) {
		delete[] data;
		std::cerr << "error write mdhd head\n";
		return -1;
	}
	delete[] data;
	return atom_size;
}


SttsAtom::SttsAtom()
{
	memset(&stts, 0, sizeof(SttsBox));
}

SttsAtom::~SttsAtom()
{

}

int SttsAtom::ParseAtom(File& file, int64_t readSize)
{
	
	// 先越过，不读取
	file.Seek(readSize);

	/*if (mediaData != nullptr) {
		char* p = mediaData.get();
		memcpy(stts.vf, p, 4);
		p += 4;
		
		char_to_num(p, 4, stts.entry);
		p += 4;
		
		stts.stArr = new Sts[stts.entry];

		for (int i(0); i < stts.entry; i++) {
			char_to_num(p, 4, stts.stArr[i].sample_cnt);
			char_to_num(p+4, 4, stts.stArr[i].sample_delta);
			p += 8;
		}

		return 0;
	}*/

	return 0;
}

int64_t SttsAtom::SerializeAtom(File& fp)
{
	// 所有的stts不能写成一组
	atom_size = 8 + 8 + 8* stts.entry;
	WriteAtomHead(fp);

	char* data = new char[atom_size - 8]();
	int offset = 4;
	num_to_char(stts.entry, data + offset, 4);
	offset += 4;
	
	for (int i(0); i < stts.entry; i++) {
		num_to_char(1, data + offset, 4);
		offset += 4;
		num_to_char(stts.sample_delta, data + offset, 4);
		offset += 4;
	}
	
	

	fp.Write(data, atom_size - 8);

	return atom_size;
}





/***************************************分割**************************************/
Atom* AtomFactory::CreateAtom(std::string boxName)
{
	return AllocAtom(boxName);
}

Atom* AtomFactory::CreateMoovTmpl(std::vector<SampleTable>& samples,File& fpFix,File& fpDamage)
{
	
	if (samples.size() < 1) {
		std::cerr << "error samples size is too less \n";
		return nullptr;
	}


	// 提取sps，pps并解析
	SampleTable spl = *(samples.begin());
	fpDamage.Seek(spl.offset, SEEK_SET);
	std::string sps, pps;
	Sps_Info info;
	memset(&info, 0, sizeof(Sps_Info));

	while (fpDamage.Pos() < (spl.offset + spl.size)) {
		int size = fpDamage.read_int();
		char* data = new char[size]();
		fpDamage.read(data, size);

		int nalType = data[0] & 0x1f;
		std::cout << "nal type " << nalType << " size " << size << std::endl;
		if (nalType == 7) { // sps
			sps.assign(data, size);
			sps_parse(data + 1, size - 1, &info);
		}
		else if (nalType == 8) { //pps
			pps.assign(data, size);
		}
		delete[] data;

		if (sps.size() && pps.size())
			break;
	}


	// 迭代samples列表，提取信息
	// 关键帧序号
	std::vector<uint32_t> keyIndex;
	// sample 大小
	std::vector<uint32_t> sampleSize;
	// sample 位置
	std::vector<uint64_t> chunkOffset;


	for (size_t id(0); id < samples.size(); id++) {

		if (samples[id].keyFrame) {
			// 从1开始计数
			keyIndex.push_back(id + 1);
		}

		sampleSize.push_back(samples[id].size);
		chunkOffset.push_back(samples[id].offset);	
	}

	int len = 0;
	char atomBuffer[4096] = {};

	// 
	Atom* moov = AllocAtom("moov");

	// -----------------  mvhd 
	Atom* mvhd = AllocAtom("mvhd");
	MVHDBOX* mvBox = static_cast<MVHDBOX*>(mvhd->ContentData());

	mvBox->media.timescale = 1000;
	mvBox->media.duration = samples.size() * mvBox->media.timescale / info.fps;


	// 取决于音频	
	mvBox->next_tid = 2;
	mvBox->rate = 1;
	mvBox->volume = 1;
	memcpy(mvBox->matrix, Martix, 36);
	moov->childAtom.push_back(mvhd);

	// ----------------- trak video
	Atom *trak = AllocAtom("trak");
	moov->childAtom.push_back(trak);

	//------------------ tkhd
	Atom* tkhd = AllocAtom("tkhd");
	TKHDBOX* tkBox = static_cast<TKHDBOX*>(tkhd->ContentData());
	tkBox->width = info.width;
	tkBox->height = info.height;
	tkBox->media.duration = mvBox->media.duration;
	tkBox->trackid = mvBox->next_tid - 1;
	tkBox->volume = mvBox->volume;
	tkBox->vf[3] = 3;
	memcpy(tkBox->matrix, Martix, 36);
	trak->childAtom.push_back(tkhd);


	//---------------- edts
	Atom* edts = AllocAtom("edts");
	// 固定头
	num_to_char(28, atomBuffer + 8, 4);
	memcpy(atomBuffer + 12, "elst", 4);
	len = 16;
	num_to_char(1, atomBuffer + len, 4);
	len += 4;
	num_to_char(mvBox->media.duration, atomBuffer + len, 4);

	// media time 为0，跳过
	// rate
	len += 8;
	num_to_char(1, atomBuffer + len, 4);
	len += 4;

	edts->SetContentData(atomBuffer, len);
	memset(atomBuffer, 0, len);
	len = 0;
	trak->childAtom.push_back(edts);


	//--------------- mdia
	Atom* vmdia = AllocAtom("mdia");
	trak->childAtom.push_back(vmdia);

	
	//--------------- mdhd
	Atom* mdhd = AllocAtom("mdhd");
	MdhdBox* mdBox = static_cast<MdhdBox*>(mdhd->ContentData());
	mdBox->media.timescale = 1000 * 1000;
	mdBox->media.duration = mvBox->media.duration * mvBox->media.timescale / mvBox->media.timescale;
	mdBox->language_code[0] = 0x55;
	mdBox->language_code[1] = 0xC4;
	vmdia->childAtom.push_back(mdhd);


	//--------------- hdlr
	Atom* vhdlr = AllocAtom("hdlr");
	vhdlr->SetContentData(vhandle, 0x2d);
	vhdlr->childAtom.push_back(vhdlr);


	//--------------- minf
	Atom* minf = AllocAtom("minf");
	vmdia->childAtom.push_back(minf);

	//--------------- vmhd
	Atom *vmhd = AllocAtom("vmhd");
	vmhd->SetContentData(vhandle, 0x14);
	minf->childAtom.push_back(vmhd);

	//--------------- dinf
	Atom* dinf = AllocAtom("dinf");
	dinf->SetContentData(dinfBox, 0x24);
	minf->childAtom.push_back(dinf);

	//--------------- stbl
	Atom* stbl = AllocAtom("stbl");
	minf->childAtom.push_back(stbl);


	//--------------- stsd 
	Atom* stsd = AllocAtom("stsd");
	// 跳过version flag
	num_to_char(1, atomBuffer + 12, 4);
	stsd->SetContentData(atomBuffer, 16);
	stbl->childAtom.push_back(stsd);
	memset(atomBuffer, 0, 16);
	
	//--------------- avc1
	Atom* avc1 = AllocAtom("avc1");
	len += 4;
	memcpy(atomBuffer + len, "acv1", 4);
	len += 4;
	// reserved 
	len += 6;
	num_to_char(1, atomBuffer + len, 2);
	len += 2;

	//class VisualSampleEntry(codingname) extends SampleEntry(codingname) {
	//	unsigned int(16) pre_defined = 0;
	//	const unsigned int(16) reserved = 0;
	//	unsigned int(32)[3] pre_defined = 0;
	//	unsigned int(16) width;
	//	unsigned int(16) height;
	//	template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
	//	template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
	//	const unsigned int(32) reserved = 0;
	//	template unsigned int(16) frame_count = 1;
	//	string[32] compressorname;
	//	template unsigned int(16) depth = 0x0018;
	//	int(16) pre_defined = -1;
	//	// other boxes from derived specifications
	//	CleanApertureBox clap; // optional
	//	PixelAspectRatioBox pasp; // optional
	//}

	len += 32;

	num_to_char(info.width, atomBuffer + len, 2);
	len += 2;
	num_to_char(info.height, atomBuffer + len, 2);
	len += 2;

	num_to_char(72, atomBuffer + len, 4);
	len += 4;
	num_to_char(72, atomBuffer + len, 4);
	len += 4;

	len += 4;

	num_to_char(1, atomBuffer + len, 2);
	len += 2;

	// string[32]  compressorname
	len += 32;

	num_to_char(24, atomBuffer + len, 2);
	len += 2;

	num_to_char(0xFFFF, atomBuffer + len, 2);
	len += 2;

	num_to_char(len, atomBuffer, 4);
	avc1->SetContentData(atomBuffer, len);
	stsd->childAtom.push_back(avc1);

	memset(atomBuffer, 0, len);
	len = 0;

	//--------------- avcC
	/*aligned(8) class AVCDecoderConfigurationRecord {
		unsigned int(8) configurationVersion = 1;
		unsigned int(8) AVCProfileIndication;
		unsigned int(8) profile_compatibility;
		unsigned int(8) AVCLevelIndication;
		bit(6) reserved = ‘111111’b;
		unsigned int(2) lengthSizeMinusOne;
		bit(3) reserved = ‘111’b;
		unsigned int(5) numOfSequenceParameterSets;
		for (i = 0; i < numOfSequenceParameterSets; i++) {
			unsigned int(16) sequenceParameterSetLength;
			bit(8 * sequenceParameterSetLength) sequenceParameterSetNALUnit;
		}
		unsigned int(8) numOfPictureParameterSets;
		for (i = 0; i < numOfPictureParameterSets; i++) {
			unsigned int(16) pictureParameterSetLength;
			bit(8 * pictureParameterSetLength) pictureParameterSetNALUnit;
		}
		if (profile_idc == 100 || profile_idc == 110 ||
			profile_idc == 122 || profile_idc == 144)
		{
			bit(6) reserved = ‘111111’b;
			unsigned int(2) chroma_format;
			bit(5) reserved = ‘11111’b;
			unsigned int(3) bit_depth_luma_minus8;
			bit(5) reserved = ‘11111’b;
			unsigned int(3) bit_depth_chroma_minus8;
			unsigned int(8) numOfSequenceParameterSetExt;
			for (i = 0; i < numOfSequenceParameterSetExt; i++) {
				unsigned int(16) sequenceParameterSetExtLength;
				bit(8 * sequenceParameterSetExtLength) sequenceParameterSetExtNALUnit;
			}
		}
	}*/

	Atom* avcC = AllocAtom("avcC");
	len += 4;
	memcpy(atomBuffer + len, "avcC", 4);
	len += 4;

	num_to_char(1, atomBuffer + len, 1);
	len += 1;

	num_to_char(info.profile_idc, atomBuffer + len, 1);
	len += 1;

	// profile_compatibility is a byte defined exactly the same as the byte which occurs between the profile_IDC and level_IDC in a sequence parameter set (SPS), as defined in ISO/IEC 14496-10
	num_to_char(0, atomBuffer + len, 1);
	len += 1;

	num_to_char(info.level, atomBuffer + len, 1);
	len += 1;

	// 6 bit reserved 3bit val + 1 is nal unit size.may 1，2，4
	// we use 4bit 
	num_to_char(0xFF, atomBuffer + len, 1);
	len += 1;

	// 3bit reserved 111b,0xE0|0x1. 5bit is indicates the number of SPSs that are used as the initial set of SPSs for decoding the AVC elementary stream.
	num_to_char(0xE1, atomBuffer + len, 1);
	len += 1;

	// sps size,data
	num_to_char(sps.size(), atomBuffer + len, 2);
	len += 2;
	memcpy(atomBuffer + len, sps.c_str(), sps.size());
	len += sps.size();

	//pps num,size,data
	num_to_char(1, atomBuffer + len, 1);
	len += 1;
	num_to_char(pps.size(), atomBuffer + len, 2);
	len += 2;
	memcpy(atomBuffer + len, pps.c_str(), pps.size());
	len += pps.size();

	// 先写入固定值
	if (info.profile_idc == 100 || info.profile_idc == 110 ||
		info.profile_idc == 122 || info.profile_idc == 144) {

		atomBuffer[len++] = 0xFD;
		atomBuffer[len++] = 0xF8;
		atomBuffer[len++] = 0xF8;
		atomBuffer[len++] = 0x00;
		len += 4;
	}
	avcC->SetContentData(atomBuffer, len);
	avc1->childAtom.push_back(avcC);
	memset(atomBuffer, 0, len);
	len = 0;
	

	Atom* stts = AllocAtom("stts");
	SttsBox* tsBox = static_cast<SttsBox*>(stts->ContentData());
	tsBox->entry = samples.size();
	tsBox->sample_delta = mdBox->media.timescale / info.fps;
	stbl->childAtom.push_back(stts);

	Atom* stss = AllocAtom("stss");
	std::vector<int>* ssBox = static_cast<std::vector<int> *>(stss->ContentData());
	ssBox->assign(keyIndex.begin(), keyIndex.end());
	stbl->childAtom.push_back(stss);

	//  stsc
	Atom* stsc = AllocAtom("stsc");
	STSCBOX* scBox = static_cast<STSCBOX*>(stsc->ContentData());
	scBox->entry = samples.size();
	stbl->childAtom.push_back(stsc);

	// stsz 
	Atom* stsz = AllocAtom("stsz");
	std::vector<int>* szBox = static_cast<std::vector<int> *>(stsz->ContentData());
	szBox->assign(sampleSize.begin(), sampleSize.end());
	stbl->childAtom.push_back(stsz);

	// stco
	Atom* stco = AllocAtom("stco");
	std::vector<uint32_t>* coBox = static_cast<std::vector<uint32_t>*>(stco->ContentData());
	coBox->assign(chunkOffset.begin(), chunkOffset.end());
	stbl->childAtom.push_back(stco);

	// udta
	Atom* udta = AllocAtom("udat");
	udta->SetContentData(udtaBox, 0x62);
	moov->childAtom.push_back(udta);
	
	return moov;
}

Atom* AtomFactory::AllocAtom(std::string boxName)
{
	Atom* atom = nullptr;
	int32_t type;
	char_to_num(boxName.c_str(), 4, type);
	// atoi 是指字符1，2，3转成数字
//	uint32_t type = atoi(p);
	switch (type)
	{
	case MVHD:
		atom = new MvhdAtom();
		break;
	case TKHD:
		atom = new TkhdAtom();
		break;
	case MDHD:
		atom = new MdhdAtom();
		break;
	case STTS:
		atom = new SttsAtom();
		break;
	case STSS:
		atom = new StssAtom();
		break;
	case STSC:
		atom = new StscAtom();
		break;
	case STSZ:
		atom = new StszAtom();
		break;
	case STCO:
		atom = new StcoAtom();
		break;
	default:
		atom = new Atom(boxName.c_str());
		break;
	}
	atom->boxType = boxName;
	return atom;
}

StssAtom::~StssAtom()
{
}

int StssAtom::ParseAtom(File& file, int64_t readSize)
{
	file.Seek(readSize);
	return 0;
}

int64_t StssAtom::SerializeAtom(File& fp)
{
	atom_size = 8 + 8 + stss.size() * 4;
	WriteAtomHead(fp);

	char *data = new char[atom_size - 8]();
	int offset = 4;

	num_to_char(stss.size(), data + offset, 4);
	offset += 4;
	int i = 0;
	for (; i < stss.size(); i++) {
		num_to_char(stss[i], data + offset, 4);
		offset += 4;
	}

	fp.Write(data, atom_size - 8);

	return atom_size;
}

StscAtom::~StscAtom()
{

}

int StscAtom::ParseAtom(File& file, int64_t readSize)
{
	file.Seek(readSize);
	return 0;
}

int64_t StscAtom::SerializeAtom(File& fp)
{
	atom_size = 8 + 8 + 12;
	WriteAtomHead(fp);

	char* data = new char[atom_size - 8]();
	int offset = 4;
	num_to_char(1, data + offset, 4);
	offset += 4;
	num_to_char(1, data + offset, 4);
	offset += 4;
	num_to_char(1, data + offset, 4);
	offset += 4;
	num_to_char(1, data + offset, 4);

	fp.Write(data, atom_size - 8);
	return atom_size;
}

StszAtom::~StszAtom()
{

}

int StszAtom::ParseAtom(File& file, int64_t readSize)
{
	return 	file.Seek(readSize); 
}

int64_t StszAtom::SerializeAtom(File& fp)
{
	atom_size = 8 + 8 + 4 + 4 * stsz.size();
	WriteAtomHead(fp);

	char* data = new char[atom_size - 8]();
	int offset = 8;
	
	
	num_to_char(stsz.size(), data + offset, 4);
	offset += 4;

	int i = 0;
	for (; i < stsz.size(); i++) {
		num_to_char(stsz[i], data + offset, 4);
		offset += 4;
	}

	fp.Write(data, atom_size - 8);
	return atom_size;
}

StcoAtom::~StcoAtom()
{

}

int StcoAtom::ParseAtom(File& file, int64_t readSize)
{
	return 	file.Seek(readSize);
}

int64_t StcoAtom::SerializeAtom(File& fp)
{
	atom_size = 8 + 8 + 4 * stco.size();
	WriteAtomHead(fp);
	char* data = new char[atom_size - 8]();
	
	int offset = 4;
	num_to_char(stco.size(), data + offset, 4);
	offset += 4;
	for (int i(0); i < stco.size(); i++) {
		num_to_char(stco[i], data + offset, 4);
		offset += 4;
	}

	fp.Write(data, offset);
	delete[] data;
	return atom_size;
}
